import * as THREE from 'three';
import URDFViewer from './urdf-viewer-element.js';
import { PointerURDFDragControls } from './URDFDragControls.js';

// urdf操纵器元件
// 显示可以用鼠标操纵的URDF模型

// 活动
// 关节鼠标悬停：当关节悬停在上方时触发
// 关节mouseout：当关节不再悬停时触发
// 操纵启动：操纵关节时启动
// 操纵端：当关节被操纵完成时开火
export default
  class URDFManipulator extends URDFViewer {
  static get observedAttributes() {
    return ['highlight-color', ...super.observedAttributes];
  }

  get disableDragging() { return this.hasAttribute('disable-dragging'); }
  set disableDragging(val) { val ? this.setAttribute('disable-dragging', !!val) : this.removeAttribute('disable-dragging'); }

  get highlightColor() { return this.getAttribute('highlight-color') || '#FFFFFF'; }
  set highlightColor(val) { val ? this.setAttribute('highlight-color', val) : this.removeAttribute('highlight-color'); }

  constructor(...args) {
    super(...args);
    // 亮点材料
    this.highlightMaterial =
      new THREE.MeshPhongMaterial({
        shininess: 10,
        color: this.highlightColor,
        emissive: this.highlightColor,
        emissiveIntensity: 0.25,
      });

    const isJoint = j => {
      return j.isURDFJoint && j.jointType !== 'fixed';
    };

    // 突出显示关节下的链接几何图形
    const highlightLinkGeometry = (m, revert) => {
      const traverse = c => {
        // 设置或恢复突出显示颜色
        if (c.type === 'Mesh') {
          if (revert) {
            c.material = c.__origMaterial;
            delete c.__origMaterial;
          } else {
            c.__origMaterial = c.material;
            c.material = this.highlightMaterial;
          }
        }

        // 看看孩子们，如果下一个孩子来了，就停下来
        // 另一个关节
        if (c === m || !isJoint(c)) {
          for (let i = 0; i < c.children.length; i++) {
            const child = c.children[i];
            if (!child.isURDFCollider) {
              traverse(c.children[i]);
            }
          }
        }
      };
      traverse(m);
    };

    const el = this.renderer.domElement;

    const dragControls = new PointerURDFDragControls(this.scene, this.camera, el);
    dragControls.onDragStart = joint => {
      this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: joint.name }));
      this.controls.enabled = false;
      this.redraw();
    };
    dragControls.onDragEnd = joint => {
      this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: joint.name }));
      this.controls.enabled = true;
      this.redraw();
    };
    dragControls.updateJoint = (joint, angle) => {
      this.setJointValue(joint.name, angle);
    };
    dragControls.onHover = joint => {
      highlightLinkGeometry(joint, false);
      this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: joint.name }));
      this.redraw();
    };
    dragControls.onUnhover = joint => {
      highlightLinkGeometry(joint, true);
      this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: joint.name }));
      this.redraw();
    };

    this.dragControls = dragControls;
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    this.dragControls.dispose();
  }

  attributeChangedCallback(attr, oldval, newval) {
    super.attributeChangedCallback(attr, oldval, newval);
    switch (attr) {
      case 'highlight-color':
        this.highlightMaterial.color.set(this.highlightColor);
        this.highlightMaterial.emissive.set(this.highlightColor);
        break;
    }
  }
};
